using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.SharpZipLib.BZip2;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Zip;

namespace CalcSharp.Core.IO
{
    public enum CompressFormat
    {
        none,
        bzip,
        gzip,
        zip
    }

    /// <summary>
    /// Helps Handling of streams
    /// </summary>
    public sealed class StreamHelper
    {
        private StreamHelper() { }
        /// <summary>
        /// Copy a stream to another stream
        /// </summary>
        /// <param name="input">The input stream (data source)</param>
        /// <param name="output">The output stream (data destination)</param>
        public static void Copy(Stream input, Stream output)
        {
            int cpy;
            byte[] buffer = new byte[4096];
            do
            {
                cpy = input.Read(buffer, 0, buffer.Length);
                output.Write(buffer, 0, cpy);
            }
            while (cpy > 0);
            output.Flush();
        }

        /// <summary>
        /// Compress a Stream
        /// </summary>
        /// <param name="input">The input stream (data source)</param>
        /// <param name="output">The compressed stream output</param>
        /// <param name="f">Compression format, if none, then StreamHelper.Copy() is called</param>
        public static void Compress(Stream input, Stream output, CompressFormat f)
        {
            int buff;
            byte[] buffer = new byte[4096];
            if (f == CompressFormat.gzip)
            {
                using (GZipOutputStream gzo = new GZipOutputStream(output, 4096))
                {
                    do
                    {
                        buff = input.Read(buffer, 0, buffer.Length);
                        gzo.Write(buffer, 0, buff);
                    }
                    while (buff > 0);
                }
            }
            else if (f == CompressFormat.bzip)
            {
                using (BZip2OutputStream bzo = new BZip2OutputStream(output, 4096))
                {
                    do
                    {
                        buff = input.Read(buffer, 0, buffer.Length);
                        bzo.Write(buffer, 0, buff);
                    }
                    while (buff > 0);
                }
            }
            else if (f == CompressFormat.zip)
            {
                using (ZipOutputStream zio = new ZipOutputStream(output))
                {
                    zio.SetLevel(9);
                    zio.UseZip64 = UseZip64.On;
                    ZipEntry ent = new ZipEntry("stream.bin");
                    ent.DateTime = DateTime.Now;
                    zio.PutNextEntry(ent);
                    do
                    {
                        buff = input.Read(buffer, 0, buffer.Length);
                        zio.Write(buffer, 0, buff);
                    }
                    while (buff > 0);
                    zio.Finish();
                }
            }
            else if (f == CompressFormat.none)
            {
                StreamHelper.Copy(input, output);
            }
        }

        /// <summary>
        /// Uncompresses a compressed stream, created by the Compress function
        /// </summary>
        /// <param name="input">The compressed stream input</param>
        /// <param name="output">The uncompressed stream output</param>
        /// <param name="f">Compression format, if none, then StreamHelper.Copy() is called</param>
        public static void UnCompres(Stream input, Stream output, CompressFormat f)
        {
            int buff;
            byte[] buffer = new byte[4096];
            if (f == CompressFormat.gzip)
            {
                using (GZipInputStream gzi = new GZipInputStream(input, 4096))
                {
                    do
                    {
                        buff = gzi.Read(buffer, 0, buffer.Length);
                        output.Write(buffer, 0, buff);
                    }
                    while (buff > 0);
                }
            }
            else if (f == CompressFormat.bzip)
            {
                using (BZip2InputStream bzi = new BZip2InputStream(input))
                {
                    do
                    {
                        buff = bzi.Read(buffer, 0, buffer.Length);
                        output.Write(buffer, 0, buff);
                    }
                    while (buff > 0);
                }
            }
            else if (f == CompressFormat.zip)
            {
                using (ZipInputStream zii = new ZipInputStream(input))
                {
                    zii.GetNextEntry();
                    do
                    {
                        buff = zii.Read(buffer, 0, buffer.Length);
                        output.Write(buffer, 0, buff);
                    }
                    while (buff > 0);
                }
            }
            else if (f == CompressFormat.none)
            {
                StreamHelper.Copy(input, output);
            }
        }
    }

    public sealed class FileHelper
    {
        private FileHelper() { }

        #region static methods
        /// <summary>
        /// gets the Application Directory
        /// </summary>
        public static string Appdir
        {
            get
            {
                return Path.GetDirectoryName(Application.ExecutablePath);
            }
        }
        /// <summary>
        /// Gets the user's profile directory
        /// </summary>
        public static string ProfileDir
        {
            get
            {
                return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            }
        }
        /// <summary>
        /// Gets the directory's files, even those which are in a subdirectory (recursive)
        /// </summary>
        /// <param name="baseDir">The directory where the search begins</param>
        /// <param name="mask">Searh pattern</param>
        /// <returns>An array with the file paths</returns>
        public static string[] GetAllFileNames(string baseDir, string mask)
        {
            List<string> fileResults = new List<string>();
            Stack<string> directoryStack = new Stack<string>();
            directoryStack.Push(baseDir);
            while (directoryStack.Count > 0 && fileResults.Count < 1000)
            {
                string currentDir = directoryStack.Pop();
                foreach (string fileName in Directory.GetFiles(currentDir, mask))
                {
                    fileResults.Add(fileName);
                }
                foreach (string directoryName in Directory.GetDirectories(currentDir))
                {
                    directoryStack.Push(directoryName);
                }
            }
            return fileResults.ToArray();
        }
        /// <summary>
        /// Calculates the MD5 hash of a file
        /// </summary>
        /// <param name="Fname">The filename to be hashed</param>
        /// <returns>The MD5 hash as sting</returns>
        public static string MD5_File(string Fname)
        {
            StringBuilder sb = new StringBuilder();
            FileStream fs = File.OpenRead(Fname);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] hash = md5.ComputeHash(fs);
            fs.Close();
            foreach (byte hex in hash) sb.Append((hex.ToString("x2")));
            return sb.ToString();
        }
        /// <summary>
        /// Calculates the SHA-1 hash of a file
        /// </summary>
        /// <param name="Fname">The filename to be hashed</param>
        /// <returns>The SHA-1 hash as sting</returns>
        public static string SHA1_File(string Fname)
        {
            StringBuilder sb = new StringBuilder();
            FileStream fs = File.OpenRead(Fname);
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            byte[] hash = sha1.ComputeHash(fs);
            fs.Close();
            foreach (byte hex in hash) sb.Append((hex.ToString("x2")));
            return sb.ToString();
        }
        /// <summary>
        /// Returns the current temp directory
        /// </summary>
        public static string TempDir
        {
            get { return System.IO.Path.GetTempPath(); }
        }
        public static string GetFilename(string path)
        {
            string[] pathstring = path.Split('\\');
            if (pathstring.Length == 1) pathstring = path.Split('/');
            return pathstring[pathstring.Length - 1];
        }
        #endregion
    }
}